/**
 *   Copyright (c) fanguangping. All rights reserved.
 *   The use and distribution terms for this software are covered by the
 *   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
 *   which can be found in the file epl-v10.html at the root of this distribution.
 *   By using this software in any fashion, you are agreeing to be bound by
 * 	 the terms of this license.
 *   You must not remove this notice, or any other, from this software.
 **/
package org.jfunny.core.sys;

import java.util.List;
import java.util.Set;

import org.jfunny.core.ds.Statement;
import org.jfunny.core.meta.Namespace;
import org.jfunny.core.sys.SysEvalable;
import org.jfunny.core.sys.SysNamespaceAware;
import org.jfunny.core.sys.SysPreparable;
import org.jfunny.core.sys.SysProperties;
import org.jfunny.core.util.StringUtil;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;

/**
 * 
 * @author fanguangping
 *
 */
public class SysEvaluator {
	public static Namespace getNamespace(Statement statement) throws Exception {
		Reflections reflections = new Reflections(
			ClasspathHelper.forPackage(SysProperties.SYS_FUNC_IMPL), new SubTypesScanner());
		Set<Class<? extends SysNamespaceAware>> classList = reflections.getSubTypesOf(SysNamespaceAware.class);
		
		for (Class clazz : classList) {
			Object object = clazz.newInstance();
			
			if (getCorrespondingClassName(statement).equals(clazz.getSimpleName())) {
				return ((SysNamespaceAware) object).getNamespace(statement);
			}
		}
		
		return null;
	}
	
	public static void prepare(Statement statement) throws Exception {
		Reflections reflections = new Reflections(
			ClasspathHelper.forPackage(SysProperties.SYS_FUNC_IMPL), new SubTypesScanner());
		Set<Class<? extends SysPreparable>> classList = reflections.getSubTypesOf(SysPreparable.class);
		
		for (Class clazz : classList) {
			Object object = clazz.newInstance();
			
			if (getCorrespondingClassName(statement).equals(clazz.getSimpleName())) {
				((SysPreparable) object).prepare(statement);
				return;
			}
		}
	}
	
	public static String eval(Statement statement) throws Exception {
		//List<Class> classList = ReflectionUtil.findClassesByPackageName(SysEvalable.class, SysProperties.SYS_FUNC_IMPL);
		Reflections reflections = new Reflections(
			ClasspathHelper.forPackage(SysProperties.SYS_FUNC_IMPL), new SubTypesScanner());
		Set<Class<? extends SysEvalable>> classList = reflections.getSubTypesOf(SysEvalable.class);
		
		for (Class clazz : classList) {
			Object object = clazz.newInstance();
			
			if (getCorrespondingClassName(statement).equals(clazz.getSimpleName())) {
				return ((SysEvalable) object).eval(statement);
			}
		}
		
		return "";
	}
	
	private static String getFunctionName(Statement statement) {
		List<Statement> list = statement.getChildren();
		String funcName = list.get(0).toString();
		funcName = StringUtil.substringAfter(funcName, "(");
		funcName = funcName.trim();
		funcName = StringUtil.substringBefore(funcName, " ");
		return funcName;
	}
	
	private static String getCorrespondingClassName(Statement statement) {
		String funcName = getFunctionName(statement);
		String[] strs = funcName.split("-");
		String className = "";
		for (String str : strs) {
			className += str.substring(0,1).toUpperCase() + str.substring(1);
		}
		return className;
	}
}
